package com.fingard.dsp.task;

import java.util.Date;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ReceiptProConfig;
import com.fingard.dsp.bank.directConfig.TaskTimerSet;
import com.fingard.util.DateHelper;

/**用于计数延时，应用场景：
 * 针对轮询执行的计划任务，实际执行时有数据处理的频率并不高，
 * 需要动态增加延时判断，如
 * 第一次无数据时，下次延时1分钟，
 * 第二次无数据时，下次延时4分钟，
 * 第二次无数据时，下次延时9分钟。
 * */
public class DelayCounter {
	
	private long zeroCount = 0;//连续无数据的次数
	private Date lastExecTime = null;
	private Date countBaseTime = null;//计算基准时间
	
	/**最大延时*/
	private int maxDelayMinutes;
	
	private int multiplyBase = 3;
	private int counterType = 0;
	
	public void setMultiplyBase(int pVal){
		multiplyBase = pVal;
	}
	
	/**@param pMaxMinutes 最大延时分钟数，总延时=轮询间隔+延时
	 * @param pCounterType 计数方式，1表示乘法（次数x基数，基数默认是3），2表示平方（次数的平方），其它表示加法*/
	public DelayCounter(int pMaxMinutes, int pCounterType){
		maxDelayMinutes = pMaxMinutes;
		counterType = pCounterType;
		lastExecTime = new Date();
		lastDtLogTime = DateHelper.addDays(new Date(), -1);
	}
	
	/**重新计数--连续无数据的次数置为0*/
	public void resetZeroCount(){
		zeroCount = 0;
		lastExecTime = new Date();
		countBaseTime = null;//重置
	}
	
	/**无数据次数加1*/
	public void increaseZeroCount(){
		zeroCount++;
		lastExecTime = new Date();
		countBaseTime = null;//重置
	}
	
	/**按无数据的次数取得应该延时的分钟数，不超过最大数，是额外延时的分钟数*/
	public long getDelayMinutes(){
		
		long nowZeroCount = zeroCount;
		
		if(nowZeroCount == 0){
			return 0;
		}
		long delayMins = 0;
		//CounterType 计数方式，1表示乘法（次数x基数，基数默认是3），2表示平方（次数的平方），其它表示加法
		if(counterType == 1){
			delayMins = zeroCount*multiplyBase;
		}else if(counterType == 2){
			delayMins = zeroCount*zeroCount;
		}else{
			delayMins = zeroCount;
		}
		if(delayMins > maxDelayMinutes){
			delayMins = maxDelayMinutes;
		}
		return delayMins;
	}
	
	/**取得预期下次执行时间*/
	public Date getExpectNextExecTime(){
		long delayMins = getDelayMinutes();
		long intervalSecs = Long.parseLong(Format.DecimalIntFormat.format(actualIntervalSecs));
		if(actualIntervalSecs>(delayMins*60)){
			return DateHelper.addSeconds(lastExecTime, intervalSecs);
		}else{
			long addSecs = delayMins*60 + intervalSecs;
			return DateHelper.addSeconds(lastExecTime, addSecs);
		}
	}
	
	/**实际轮询间隔秒数*/
	private double actualIntervalSecs;
	
	public boolean isDelay(){
		if(zeroCount > 0){
			Date cBaseTime = countBaseTime;
			if(cBaseTime == null){//第一次调用延时
				//防并发
				cBaseTime = new Date();
				countBaseTime = cBaseTime;
				//实际轮询间隔秒数
				actualIntervalSecs = DateHelper.getDifferSecs(cBaseTime, lastExecTime);
			}
			
			//已经延时的分钟数，用于比较是否已到需要延时的分钟数
			double diffBaseMins = DateHelper.getDifferMins(new Date(), cBaseTime);
			long delayMins = getDelayMinutes();
			
			//总延时=轮询间隔+额外延时
			if(diffBaseMins < delayMins){//小于需要增加延时的分钟
				return true;
			}
		}
		return false;
	}
	/**记录上次详细日志输出的时间，两小时输出一次详细信息，以减少日志量*/
	private Date lastDtLogTime;
	
	/**是否输出详细日志，为减少日志量，间隔一定时间再输出详细日志*/
	public boolean getOutDetailLog(ReceiptProConfig pConfig, TaskTimerSet pTimerSet){
		Date nowTime = new Date();
		double diffHours = DateHelper.getDifferHours(nowTime, lastDtLogTime);
		//每天几点开始记录详细日志，默认5点后
		int defHour = pConfig.getValueAsInt("dtLogBeginHour", 5, "");
		int dtLogBeginHour = pTimerSet.getParamAsInt("dtLogBeginHour", defHour);
		
		//详细日志间隔小时数
		int defInterval = pConfig.getValueAsInt("dtLogInterval", 2, "");
		int dtLogInterval = pTimerSet.getParamAsInt("dtLogInterval", defInterval);
		if(diffHours > dtLogInterval){
			if(DateHelper.getHour(nowTime) >= dtLogBeginHour){
				lastDtLogTime = nowTime;
				return true;
			}
		}
		return false;
	}
}
